package com.liyuncong.algorithm.algorithm_kmeans.util;

import java.util.List;

import com.liyuncong.algorithm.algorithm_kmeans.entity.Cluster;
import com.liyuncong.algorithm.algorithm_similarity.entity.Vector;

public class ClusterUtil {
	/**
	 * 获得一些向量的中心
	 * @param elementList
	 * @return
	 * @throws IllegalAccessException
	 */
	public static Vector getCenter(List<Vector> elementList) throws IllegalAccessException {
		int vectorNum = elementList.size();
		// 构造一个跟elementList中向量的长度一样的向量
		Vector vectorSum = new Vector(new float[elementList.get(0).getLength()]);
		for(int i = 0; i < vectorNum; i++) {
			vectorSum = vectorPlus(vectorSum, elementList.get(i));
		}
		Vector center = vectorDivide(vectorSum, vectorNum);
		return center;
	}
	
	/**
	 * 两个向量相加
	 * @param vector1
	 * @param vector2
	 * @return
	 * @throws IllegalAccessException
	 */
	private static Vector vectorPlus(Vector vector1, Vector vector2) throws IllegalAccessException {
		int elementNum = vector1.getLength();
		if (elementNum != vector2.getLength()) {
			throw new IllegalAccessException("vector1'length is not equal to"
					+ "vector2's length");
		}
		float[] elementArr1 = vector1.getVector();
		float[] elementArr2 = vector2.getVector();
		for(int i= 0; i < elementNum; i++) {
			elementArr1[i] += elementArr2[i];
		}
		return new Vector(elementArr1);
	}
	
	/**
	 * 向量除以一个标量
	 * @param vector
	 * @param num
	 * @return
	 */
	private static Vector vectorDivide(Vector vector, int num) {
		float[] elementArr = vector.getVector();
		int elementNum = vector.getLength();
		for(int i = 0; i < elementNum; i++) {
			elementArr[i] /= num;
		}
		return new Vector(elementArr);
	}
	
	/**
	 * 计算一个聚类的误差平方和
	 * @param cluster
	 * @return
	 */
	public static float computeSSE(Cluster cluster) {
		float sse = 0;
		
		Vector center = cluster.getCenter();
		List<Vector> elementList = cluster.getElementList();
		int elementNum = elementList.size();
		for(int i = 0; i < elementNum; i++) {
			float similarity = center.distanceTo(elementList.get(i));
			sse += Math.pow(similarity, 2);
		}
		
		return sse;
	}
	
	/**
	 * 计算所有聚类的误差平方和
	 * @param cluster
	 * @return
	 */
	public static float computeSSE(List<Cluster> clusters) {
		float sse = 0;
		
		int clusterNum = clusters.size();
		for(int i = 0; i < clusterNum; i++) {
			sse += computeSSE(clusters.get(i));
		}
		
		return sse;
	}
	
	/**
	 * 把向量转化为字符串
	 * @param vector
	 * @return
	 */
	public static String vectorTostring(Vector vector) {
		float[] elementArray = vector.getVector();
		String elementStr = "";
		for(int i = 0; i < elementArray.length; i++) {
			elementStr += elementArray[i];
			if (i != elementArray.length - 1) {
				elementStr += " ";
			}
		}
		return elementStr;
	}
	
	public static void printVector(Vector vector) {
		System.out.println(vectorTostring(vector));
	}
	
	/**
	 * 打印聚类：长度、元素和中心
	 * @param cluster
	 */
	public static void printCluster(Cluster cluster) {
		System.out.println("---------------------");
		int clusterSize = cluster.getElementList().size();
		System.out.println("length： " + clusterSize);
		System.out.println("elements： ");
		for(int i= 0; i < clusterSize; i++) {
			System.out.println(ClusterUtil.vectorTostring(cluster.getElementList().get(i)));

		}
		System.out.println("center： " + ClusterUtil.vectorTostring(cluster.getCenter()));
	}
}
